home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / ctlr.c < prev    next >
C/C++ Source or Header  |  2001-06-23  |  47KB  |  2,055 lines

  1. /*
  2.  * Modifications Copyright 1993, 1994, 1995, 1996, 1999, 2000 by Paul Mattes.
  3.  * Original X11 Port Copyright 1990 by Jeff Sparkes.
  4.  *  Permission to use, copy, modify, and distribute this software and its
  5.  *  documentation for any purpose and without fee is hereby granted,
  6.  *  provided that the above copyright notice appear in all copies and that
  7.  *  both that copyright notice and this permission notice appear in
  8.  *  supporting documentation.
  9.  *
  10.  * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332.
  11.  *  All Rights Reserved.  GTRC hereby grants public use of this software.
  12.  *  Derivative works based on this software must incorporate this copyright
  13.  *  notice.
  14.  */
  15.  
  16. /*
  17.  *    ctlr.c
  18.  *        This module handles interpretation of the 3270 data stream and
  19.  *        maintenance of the 3270 device state.  It was split out from
  20.  *        screen.c, which handles X operations.
  21.  *
  22.  */
  23.  
  24. #include "globals.h"
  25. #include <errno.h>
  26. #include "3270ds.h"
  27. #include "appres.h"
  28. #include "ctlr.h"
  29. #include "screen.h"
  30. #include "cg.h"
  31. #include "resources.h"
  32.  
  33. #include "ctlrc.h"
  34. #include "ftc.h"
  35. #include "ft_cutc.h"
  36. #include "hostc.h"
  37. #include "kybdc.h"
  38. #include "macrosc.h"
  39. #include "popupsc.h"
  40. #include "screenc.h"
  41. #include "scrollc.h"
  42. #include "selectc.h"
  43. #include "sfc.h"
  44. #include "statusc.h"
  45. #include "tablesc.h"
  46. #include "telnetc.h"
  47. #include "trace_dsc.h"
  48. #include "utilc.h"
  49.  
  50. /* Externals: kybd.c */
  51. extern unsigned char aid;
  52.  
  53. /* Globals */
  54. int             ROWS, COLS;
  55. int             maxROWS, maxCOLS;
  56. int        ov_rows, ov_cols;
  57. int             model_num;
  58. int             cursor_addr, buffer_addr;
  59. Boolean         screen_alt = True;    /* alternate screen? */
  60. Boolean         is_altbuffer = False;
  61. unsigned char  *screen_buf;    /* 3270 display buffer */
  62. struct ea      *ea_buf;        /* 3270 extended attribute buffer */
  63. Boolean         formatted = False;    /* set in screen_disp */
  64. Boolean         screen_changed = False;
  65. int             first_changed = -1;
  66. int             last_changed = -1;
  67. unsigned char   reply_mode = SF_SRM_FIELD;
  68. int             crm_nattr = 0;
  69. unsigned char   crm_attr[16];
  70.  
  71. /* Statics */
  72. static unsigned char *ascreen_buf;    /* alternate 3270 display buffer */
  73. static struct ea *aea_buf;    /* alternate 3270 extended attribute buffer */
  74. static unsigned char *zero_buf;    /* empty buffer, for area clears */
  75. static void set_formatted(void);
  76. static void ctlr_blanks(void);
  77. static unsigned char fake_fa;
  78. static struct ea fake_ea;
  79. static Boolean  trace_primed = False;
  80. static unsigned char default_fg;
  81. static unsigned char default_gr;
  82. static unsigned char default_cs;
  83. static void    ctlr_half_connect(Boolean ignored);
  84. static void    ctlr_connect(Boolean ignored);
  85. static int    sscp_start;
  86. static void ticking_stop(void);
  87.  
  88. /*
  89.  * code_table is used to translate buffer addresses and attributes to the 3270
  90.  * datastream representation
  91.  */
  92. static unsigned char    code_table[64] = {
  93.     0x40, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
  94.     0xC8, 0xC9, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
  95.     0x50, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
  96.     0xD8, 0xD9, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
  97.     0x60, 0x61, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
  98.     0xE8, 0xE9, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
  99.     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
  100.     0xF8, 0xF9, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
  101. };
  102.  
  103. #define IsBlank(c)    ((c == CG_null) || (c == CG_space))
  104.  
  105. #define ALL_CHANGED    { \
  106.     screen_changed = True; \
  107.     if (IN_ANSI) { first_changed = 0; last_changed = ROWS*COLS; } }
  108. #define REGION_CHANGED(f, l)    { \
  109.     screen_changed = True; \
  110.     if (IN_ANSI) { \
  111.         if (first_changed == -1 || f < first_changed) first_changed = f; \
  112.         if (last_changed == -1 || l > last_changed) last_changed = l; } }
  113. #define ONE_CHANGED(n)    REGION_CHANGED(n, n+1)
  114.  
  115. #define DECODE_BADDR(c1, c2) \
  116.     ((((c1) & 0xC0) == 0x00) ? \
  117.     (((c1) & 0x3F) << 8) | (c2) : \
  118.     (((c1) & 0x3F) << 6) | ((c2) & 0x3F))
  119.  
  120. #define ENCODE_BADDR(ptr, addr) { \
  121.     if ((addr) > 0xfff) { \
  122.         *(ptr)++ = ((addr) >> 8) & 0x3F; \
  123.         *(ptr)++ = (addr) & 0xFF; \
  124.     } else { \
  125.         *(ptr)++ = code_table[((addr) >> 6) & 0x3F]; \
  126.         *(ptr)++ = code_table[(addr) & 0x3F]; \
  127.     } \
  128.     }
  129.  
  130. /*
  131.  * Initialize the emulated 3270 hardware.
  132.  */
  133. void
  134. ctlr_init(unsigned cmask unused)
  135. {
  136.     /* Register callback routines. */
  137.     register_schange(ST_HALF_CONNECT, ctlr_half_connect);
  138.     register_schange(ST_CONNECT, ctlr_connect);
  139.     register_schange(ST_3270_MODE, ctlr_connect);
  140. }
  141. /*
  142.  * Reinitialize the emulated 3270 hardware.
  143.  */
  144. void
  145. ctlr_reinit(unsigned cmask)
  146. {
  147.     if (cmask & MODEL_CHANGE) {
  148.         /* Allocate buffers */
  149.         if (screen_buf)
  150.             Free((char *)screen_buf);
  151.         screen_buf = (unsigned char *)Calloc(sizeof(unsigned char),
  152.             maxROWS * maxCOLS);
  153.         if (ea_buf)
  154.             Free((char *)ea_buf);
  155.         ea_buf = (struct ea *)Calloc(sizeof(struct ea),
  156.             maxROWS * maxCOLS);
  157.         if (ascreen_buf)
  158.             Free((char *)ascreen_buf);
  159.         ascreen_buf = (unsigned char *)Calloc(sizeof(unsigned char),
  160.             maxROWS * maxCOLS);
  161.         if (aea_buf)
  162.             Free((char *)aea_buf);
  163.         aea_buf = (struct ea *)Calloc(sizeof(struct ea),
  164.             maxROWS * maxCOLS);
  165.         if (zero_buf)
  166.             Free((char *)zero_buf);
  167.         zero_buf = (unsigned char *)Calloc(sizeof(struct ea),
  168.             maxROWS * maxCOLS);
  169.         cursor_addr = 0;
  170.         buffer_addr = 0;
  171.     }
  172. }
  173.  
  174. /*
  175.  * Deal with the relationships between model numbers and rows/cols.
  176.  */
  177. void
  178. set_rows_cols(int mn, int ovc, int ovr)
  179. {
  180.     int defmod;
  181.  
  182.     switch (mn) {
  183.     case 2:
  184.         maxCOLS = COLS = 80;
  185.         maxROWS = ROWS = 24; 
  186.         model_num = 2;
  187.         break;
  188.     case 3:
  189.         maxCOLS = COLS = 80;
  190.         maxROWS = ROWS = 32; 
  191.         model_num = 3;
  192.         break;
  193.     case 4:
  194. #if defined(RESTRICT_3279) /*[*/
  195.         if (appres.m3279) {
  196.             Warning("No 3279 Model 4, defaulting to Model 3");
  197.             set_rows_cols("3", ovc, ovr);
  198.             return;
  199.         }
  200. #endif /*]*/
  201.         maxCOLS = COLS = 80;
  202.         maxROWS = ROWS = 43; 
  203.         model_num = 4;
  204.         break;
  205.     case 5:
  206. #if defined(RESTRICT_3279) /*[*/
  207.         if (appres.m3279) {
  208.             Warning("No 3279 Model 5, defaulting to Model 3");
  209.             set_rows_cols(3, ovc, ovr);
  210.             return;
  211.         }
  212. #endif /*]*/
  213.         maxCOLS = COLS = 132;
  214.         maxROWS = ROWS = 27; 
  215.         model_num = 5;
  216.         break;
  217.     default:
  218. #if defined(RESTRICT_3279) /*[*/
  219.         defmod = appres.m3279 ? 3 : 4;
  220. #else /*][*/
  221.         defmod = 4;
  222. #endif
  223.         {
  224.             char mnb[2];
  225.  
  226.             mnb[0] = defmod + '0';
  227.             mnb[1] = '\0';
  228.             xs_warning("Unknown model, defaulting to %s", mnb);
  229.         }
  230.         set_rows_cols(defmod, ovc, ovr);
  231.         return;
  232.     }
  233.  
  234.     /* Apply oversize. */
  235.     ov_cols = 0;
  236.     ov_rows = 0;
  237.     if (ovc != 0 || ovr != 0) {
  238.         if (ovc <= 0 || ovr <= 0)
  239.             popup_an_error("Invalid %s %dx%d:\nNegative or zero",
  240.                 ResOversize, ovc, ovr);
  241.         else if (ovc * ovr >= 0x4000)
  242.             popup_an_error("Invalid %s %dx%d:\nToo big",
  243.                 ResOversize, ovc, ovr);
  244.         else if (ovc > 0 && ovc < maxCOLS)
  245.             popup_an_error("Invalid %s cols (%d):\nLess than model %d cols (%d)",
  246.                 ResOversize, ovc, model_num, maxCOLS);
  247.         else if (ovr > 0 && ovr < maxROWS)
  248.             popup_an_error("Invalid %s rows (%d):\nLess than model %d rows (%d)",
  249.                 ResOversize, ovr, model_num, maxROWS);
  250.         else {
  251.             ov_cols = maxCOLS = COLS = ovc;
  252.             ov_rows = maxROWS = ROWS = ovr;
  253.         }
  254.     }
  255.  
  256.     /* Update the model name. */
  257.     (void) sprintf(model_name, "327%c-%d%s",
  258.         appres.m3279 ? '9' : '8',
  259.         model_num,
  260.         appres.extended ? "-E" : "");
  261. }
  262.  
  263.  
  264. /*
  265.  * Set the formatted screen flag.  A formatted screen is a screen that
  266.  * has at least one field somewhere on it.
  267.  */
  268. static void
  269. set_formatted(void)
  270. {
  271.     register int    baddr;
  272.  
  273.     formatted = False;
  274.     baddr = 0;
  275.     do {
  276.         if (IS_FA(screen_buf[baddr])) {
  277.             formatted = True;
  278.             break;
  279.         }
  280.         INC_BA(baddr);
  281.     } while (baddr != 0);
  282. }
  283.  
  284. /*
  285.  * Called when a host is half connected.
  286.  */
  287. static void
  288. ctlr_half_connect(Boolean ignored unused)
  289. {
  290.     ticking_start(True);
  291. }
  292.  
  293.  
  294. /*
  295.  * Called when a host connects, disconnects, or changes ANSI/3270 modes.
  296.  */
  297. static void
  298. ctlr_connect(Boolean ignored unused)
  299. {
  300.     ticking_stop();
  301.     status_untiming();
  302.  
  303.     if (ever_3270)
  304.         fake_fa = 0xE0;
  305.     else
  306.         fake_fa = 0xC4;
  307.     if (!IN_3270 || (IN_SSCP && (kybdlock & KL_OIA_TWAIT))) {
  308.         kybdlock_clr(KL_OIA_TWAIT, "ctlr_connect");
  309.         status_reset();
  310.     }
  311.  
  312.     default_fg = 0x00;
  313.     default_gr = 0x00;
  314.     default_cs = 0x00;
  315.     reply_mode = SF_SRM_FIELD;
  316.     crm_nattr = 0;
  317. }
  318.  
  319.  
  320. /*
  321.  * Find the field attribute for the given buffer address.  Return its address
  322.  * rather than its value.
  323.  */
  324. unsigned char *
  325. get_field_attribute(register int baddr)
  326. {
  327.     int    sbaddr;
  328.  
  329.     if (!formatted)
  330.         return &fake_fa;
  331.  
  332.     sbaddr = baddr;
  333.     do {
  334.         if (IS_FA(screen_buf[baddr]))
  335.             return &(screen_buf[baddr]);
  336.         DEC_BA(baddr);
  337.     } while (baddr != sbaddr);
  338.     return &fake_fa;
  339. }
  340.  
  341. /*
  342.  * Find the field attribute for the given buffer address, bounded by another
  343.  * buffer address.  Return the attribute in a parameter.
  344.  *
  345.  * Returns True if an attribute is found, False if boundary hit.
  346.  */
  347. Boolean
  348. get_bounded_field_attribute(register int baddr, register int bound, unsigned char *fa_out)
  349. {
  350.     int    sbaddr;
  351.  
  352.     if (!formatted) {
  353.         *fa_out = fake_fa;
  354.         return True;
  355.     }
  356.  
  357.     sbaddr = baddr;
  358.     do {
  359.         if (IS_FA(screen_buf[baddr])) {
  360.             *fa_out = screen_buf[baddr];
  361.             return True;
  362.         }
  363.         DEC_BA(baddr);
  364.     } while (baddr != sbaddr && baddr != bound);
  365.  
  366.     /* Screen is unformatted (and 'formatted' is inaccurate). */
  367.     if (baddr == sbaddr) {
  368.         *fa_out = fake_fa;
  369.         return True;
  370.     }
  371.  
  372.     /* Wrapped to boundary. */
  373.     return False;
  374. }
  375.  
  376. /*
  377.  * Given the address of a field attribute, return the address of the
  378.  * extended attribute structure.
  379.  */
  380. struct ea *
  381. fa2ea(unsigned char *fa)
  382. {
  383.     if (fa == &fake_fa)
  384.         return &fake_ea;
  385.     else
  386.         return &ea_buf[fa - screen_buf];
  387. }
  388.  
  389. /*
  390.  * Find the next unprotected field.  Returns the address following the
  391.  * unprotected attribute byte, or 0 if no nonzero-width unprotected field
  392.  * can be found.
  393.  */
  394. int
  395. next_unprotected(int baddr0)
  396. {
  397.     register int baddr, nbaddr;
  398.  
  399.     nbaddr = baddr0;
  400.     do {
  401.         baddr = nbaddr;
  402.         INC_BA(nbaddr);
  403.         if (IS_FA(screen_buf[baddr]) &&
  404.             !FA_IS_PROTECTED(screen_buf[baddr]) &&
  405.             !IS_FA(screen_buf[nbaddr]))
  406.             return nbaddr;
  407.     } while (nbaddr != baddr0);
  408.     return 0;
  409. }
  410.  
  411. /*
  412.  * Perform an erase command, which may include changing the (virtual) screen
  413.  * size.
  414.  */
  415. void
  416. ctlr_erase(Boolean alt)
  417. {
  418.     kybd_inhibit(False);
  419.  
  420.     ctlr_clear(True);
  421.  
  422.     /* Let a script go. */
  423.     sms_host_output();
  424.  
  425.     if (alt == screen_alt)
  426.         return;
  427.  
  428.     screen_disp();
  429.  
  430.     if (alt) {
  431.         /* Going from 24x80 to maximum. */
  432.         screen_disp();
  433.         ROWS = maxROWS;
  434.         COLS = maxCOLS;
  435.     } else {
  436.         /* Going from maximum to 24x80. */
  437.         if (maxROWS > 24 || maxCOLS > 80) {
  438.             if (*debugging_font) {
  439.                 ctlr_blanks();
  440.                 screen_disp();
  441.             }
  442.             ROWS = 24;
  443.             COLS = 80;
  444.         }
  445.     }
  446.  
  447.     screen_alt = alt;
  448. }
  449.  
  450.  
  451. /*
  452.  * Interpret an incoming 3270 command.
  453.  */
  454. enum pds
  455. process_ds(unsigned char *buf, int buflen)
  456. {
  457.     if (!buflen)
  458.         return PDS_OKAY_NO_OUTPUT;
  459.  
  460.     scroll_to_bottom();
  461.  
  462.     trace_ds("< ");
  463.  
  464.     switch (buf[0]) {    /* 3270 command */
  465.     case CMD_EAU:    /* erase all unprotected */
  466.     case SNA_CMD_EAU:
  467.         trace_ds("EraseAllUnprotected\n");
  468.         ctlr_erase_all_unprotected();
  469.         return PDS_OKAY_NO_OUTPUT;
  470.         break;
  471.     case CMD_EWA:    /* erase/write alternate */
  472.     case SNA_CMD_EWA:
  473.         trace_ds("EraseWriteAlternate");
  474.         ctlr_erase(True);
  475.         ctlr_write(buf, buflen, True);
  476.         return PDS_OKAY_NO_OUTPUT;
  477.         break;
  478.     case CMD_EW:    /* erase/write */
  479.     case SNA_CMD_EW:
  480.         trace_ds("EraseWrite");
  481.         ctlr_erase(False);
  482.         ctlr_write(buf, buflen, True);
  483.         return PDS_OKAY_NO_OUTPUT;
  484.         break;
  485.     case CMD_W:    /* write */
  486.     case SNA_CMD_W:
  487.         trace_ds("Write");
  488.         ctlr_write(buf, buflen, False);
  489.         return PDS_OKAY_NO_OUTPUT;
  490.         break;
  491.     case CMD_RB:    /* read buffer */
  492.     case SNA_CMD_RB:
  493.         trace_ds("ReadBuffer\n");
  494.         ctlr_read_buffer(aid);
  495.         return PDS_OKAY_OUTPUT;
  496.         break;
  497.     case CMD_RM:    /* read modifed */
  498.     case SNA_CMD_RM:
  499.         trace_ds("ReadModified\n");
  500.         ctlr_read_modified(aid, False);
  501.         return PDS_OKAY_OUTPUT;
  502.         break;
  503.     case CMD_RMA:    /* read modifed all */
  504.     case SNA_CMD_RMA:
  505.         trace_ds("ReadModifiedAll\n");
  506.         ctlr_read_modified(aid, True);
  507.         return PDS_OKAY_OUTPUT;
  508.         break;
  509.     case CMD_WSF:    /* write structured field */
  510.     case SNA_CMD_WSF:
  511.         trace_ds("WriteStructuredField");
  512.         return write_structured_field(buf, buflen);
  513.         break;
  514.     case CMD_NOP:    /* no-op */
  515.         trace_ds("NoOp\n");
  516.         return PDS_OKAY_NO_OUTPUT;
  517.         break;
  518.     default:
  519.         /* unknown 3270 command */
  520.         popup_an_error("Unknown 3270 Data Stream command: 0x%X\n",
  521.             buf[0]);
  522.         return PDS_BAD_CMD;
  523.     }
  524. }
  525.  
  526. /*
  527.  * Functions to insert SA attributes into the inbound data stream.
  528.  */
  529. static void
  530. insert_sa1(unsigned char attr, unsigned char value, unsigned char *currentp, Boolean *anyp)
  531. {
  532.     if (value == *currentp)
  533.         return;
  534.     *currentp = value;
  535.     space3270out(3);
  536.     *obptr++ = ORDER_SA;
  537.     *obptr++ = attr;
  538.     *obptr++ = value;
  539.     if (*anyp)
  540.         trace_ds("'");
  541.     trace_ds(" SetAttribute(%s)", see_efa(attr, value));
  542.     *anyp = False;
  543. }
  544.  
  545. static void
  546. insert_sa(int baddr, unsigned char *current_fgp, unsigned char *current_grp, unsigned char *current_csp, Boolean *anyp)
  547. {
  548.     if (reply_mode != SF_SRM_CHAR)
  549.         return;
  550.  
  551.     if (memchr((char *)crm_attr, XA_FOREGROUND, crm_nattr))
  552.         insert_sa1(XA_FOREGROUND, ea_buf[baddr].fg, current_fgp, anyp);
  553.     if (memchr((char *)crm_attr, XA_HIGHLIGHTING, crm_nattr)) {
  554.         unsigned char gr;
  555.  
  556.         gr = ea_buf[baddr].gr;
  557.         if (gr)
  558.             gr |= 0xf0;
  559.         insert_sa1(XA_HIGHLIGHTING, gr, current_grp, anyp);
  560.     }
  561.     if (memchr((char *)crm_attr, XA_CHARSET, crm_nattr)) {
  562.         unsigned char cs;
  563.  
  564.         cs = ea_buf[baddr].cs & CS_MASK;
  565.         if (cs)
  566.             cs |= 0xf0;
  567.         insert_sa1(XA_CHARSET, cs, current_csp, anyp);
  568.     }
  569. }
  570.  
  571.  
  572. /*
  573.  * Process a 3270 Read-Modified command and transmit the data back to the
  574.  * host.
  575.  */
  576. void
  577. ctlr_read_modified(unsigned char aid_byte, Boolean all)
  578. {
  579.     register int    baddr, sbaddr;
  580.     Boolean        send_data = True;
  581.     Boolean        short_read = False;
  582.     unsigned char    current_fg = 0x00;
  583.     unsigned char    current_gr = 0x00;
  584.     unsigned char    current_cs = 0x00;
  585.  
  586.     if (IN_SSCP && aid_byte != AID_ENTER)
  587.         return;
  588.  
  589.     trace_ds("> ");
  590.     obptr = obuf;
  591.  
  592.     switch (aid_byte) {
  593.  
  594.         case AID_SYSREQ:            /* test request */
  595.         space3270out(4);
  596.         *obptr++ = 0x01;    /* soh */
  597.         *obptr++ = 0x5b;    /*  %  */
  598.         *obptr++ = 0x61;    /*  /  */
  599.         *obptr++ = 0x02;    /* stx */
  600.         trace_ds("SYSREQ");
  601.         break;
  602.  
  603.         case AID_PA1:            /* short-read AIDs */
  604.         case AID_PA2:
  605.         case AID_PA3:
  606.         case AID_CLEAR:
  607.         if (!all)
  608.             short_read = True;
  609.         /* fall through... */
  610.  
  611.         case AID_SELECT:            /* No data on READ MODIFIED */
  612.         if (!all)
  613.             send_data = False;
  614.         /* fall through... */
  615.  
  616.         default:                /* ordinary AID */
  617.         if (!IN_SSCP) {
  618.             space3270out(3);
  619.             *obptr++ = aid_byte;
  620.             trace_ds(see_aid(aid_byte));
  621.             if (short_read)
  622.                 goto rm_done;
  623.             ENCODE_BADDR(obptr, cursor_addr);
  624.             trace_ds(rcba(cursor_addr));
  625.         } else {
  626.             space3270out(1);    /* just in case */
  627.         }
  628.         break;
  629.     }
  630.  
  631.     baddr = 0;
  632.     if (formatted) {
  633.         /* find first field attribute */
  634.         do {
  635.             if (IS_FA(screen_buf[baddr]))
  636.                 break;
  637.             INC_BA(baddr);
  638.         } while (baddr != 0);
  639.         sbaddr = baddr;
  640.         do {
  641.             if (FA_IS_MODIFIED(screen_buf[baddr])) {
  642.                 Boolean    any = False;
  643.  
  644.                 INC_BA(baddr);
  645.                 space3270out(3);
  646.                 *obptr++ = ORDER_SBA;
  647.                 ENCODE_BADDR(obptr, baddr);
  648.                 trace_ds(" SetBufferAddress%s", rcba(baddr));
  649.                 while (!IS_FA(screen_buf[baddr])) {
  650.                     if (send_data &&
  651.                         screen_buf[baddr]) {
  652.                         insert_sa(baddr,
  653.                             ¤t_fg,
  654.                             ¤t_gr,
  655.                             ¤t_cs,
  656.                             &any);
  657.                         if (ea_buf[baddr].cs & CS_GE) {
  658.                             space3270out(1);
  659.                             *obptr++ = ORDER_GE;
  660.                             if (any)
  661.                                 trace_ds("'");
  662.                             trace_ds(" GraphicEscape");
  663.                             any = False;
  664.                         }
  665.                         space3270out(1);
  666.                         *obptr++ = cg2ebc[screen_buf[baddr]];
  667.                         if (!any)
  668.                             trace_ds(" '");
  669.                         trace_ds("%s", see_ebc(cg2ebc[screen_buf[baddr]]));
  670.                         any = True;
  671.                     }
  672.                     INC_BA(baddr);
  673.                 }
  674.                 if (any)
  675.                     trace_ds("'");
  676.             }
  677.             else {    /* not modified - skip */
  678.                 do {
  679.                     INC_BA(baddr);
  680.                 } while (!IS_FA(screen_buf[baddr]));
  681.             }
  682.         } while (baddr != sbaddr);
  683.     } else {
  684.         Boolean    any = False;
  685.         int nbytes = 0;
  686.  
  687.         /*
  688.          * If we're in SSCP-LU mode, the starting point is where the
  689.          * host left the cursor.
  690.          */
  691.         if (IN_SSCP)
  692.             baddr = sscp_start;
  693.  
  694.         do {
  695.             if (screen_buf[baddr]) {
  696.                 insert_sa(baddr,
  697.                     ¤t_fg,
  698.                     ¤t_gr,
  699.                     ¤t_cs,
  700.                     &any);
  701.                 if (ea_buf[baddr].cs & CS_GE) {
  702.                     space3270out(1);
  703.                     *obptr++ = ORDER_GE;
  704.                     if (any)
  705.                         trace_ds("' ");
  706.                     trace_ds(" GraphicEscape ");
  707.                     any = False;
  708.                 }
  709.                 space3270out(1);
  710.                 *obptr++ = cg2ebc[screen_buf[baddr]];
  711.                 if (!any)
  712.                     trace_ds("'");
  713.                 trace_ds(see_ebc(cg2ebc[screen_buf[baddr]]));
  714.                 any = True;
  715.                 nbytes++;
  716.             }
  717.             INC_BA(baddr);
  718.  
  719.             /*
  720.              * If we're in SSCP-LU mode, end the return value at
  721.              * 255 bytes, or where the screen wraps.
  722.              */
  723.             if (IN_SSCP && (nbytes >= 255 || !baddr))
  724.                 break;
  725.         } while (baddr != 0);
  726.         if (any)
  727.             trace_ds("'");
  728.     }
  729.  
  730.     rm_done:
  731.     trace_ds("\n");
  732.     net_output();
  733. }
  734.  
  735. /*
  736.  * Calculate the proper 3270 DS value for an internal field attribute.
  737.  */
  738. static unsigned char
  739. calc_fa(unsigned char fa)
  740. {
  741.     register unsigned char r = 0x00;
  742.  
  743.     if (FA_IS_PROTECTED(fa))
  744.         r |= 0x20;
  745.     if (FA_IS_NUMERIC(fa))
  746.         r |= 0x10;
  747.     if (FA_IS_MODIFIED(fa))
  748.         r |= 0x01;
  749.     r |= ((fa & FA_INTENSITY) << 2);
  750.     return r;
  751. }
  752.  
  753. /*
  754.  * Process a 3270 Read-Buffer command and transmit the data back to the
  755.  * host.
  756.  */
  757. void
  758. ctlr_read_buffer(unsigned char aid_byte)
  759. {
  760.     register int    baddr;
  761.     unsigned char    fa;
  762.     Boolean        any = False;
  763.     int        attr_count = 0;
  764.     unsigned char    current_fg = 0x00;
  765.     unsigned char    current_gr = 0x00;
  766.     unsigned char    current_cs = 0x00;
  767.  
  768.     trace_ds("> ");
  769.     obptr = obuf;
  770.  
  771.     space3270out(3);
  772.     *obptr++ = aid_byte;
  773.     ENCODE_BADDR(obptr, cursor_addr);
  774.     trace_ds("%s%s", see_aid(aid_byte), rcba(cursor_addr));
  775.  
  776.     baddr = 0;
  777.     do {
  778.         if (IS_FA(screen_buf[baddr])) {
  779.             if (reply_mode == SF_SRM_FIELD) {
  780.                 space3270out(2);
  781.                 *obptr++ = ORDER_SF;
  782.             } else {
  783.                 space3270out(4);
  784.                 *obptr++ = ORDER_SFE;
  785.                 attr_count = obptr - obuf;
  786.                 *obptr++ = 1; /* for now */
  787.                 *obptr++ = XA_3270;
  788.             }
  789.             fa = calc_fa(screen_buf[baddr]);
  790.             *obptr++ = code_table[fa];
  791.             if (any)
  792.                 trace_ds("'");
  793.             trace_ds(" StartField%s%s%s",
  794.                 (reply_mode == SF_SRM_FIELD) ? "" : "Extended",
  795.                 rcba(baddr), see_attr(fa));
  796.             if (reply_mode != SF_SRM_FIELD) {
  797.                 if (ea_buf[baddr].fg) {
  798.                     space3270out(2);
  799.                     *obptr++ = XA_FOREGROUND;
  800.                     *obptr++ = ea_buf[baddr].fg;
  801.                     trace_ds("%s", see_efa(XA_FOREGROUND,
  802.                         ea_buf[baddr].fg));
  803.                     (*(obuf + attr_count))++;
  804.                 }
  805.                 if (ea_buf[baddr].gr) {
  806.                     space3270out(2);
  807.                     *obptr++ = XA_HIGHLIGHTING;
  808.                     *obptr++ = ea_buf[baddr].gr | 0xf0;
  809.                     trace_ds("%s", see_efa(XA_HIGHLIGHTING,
  810.                         ea_buf[baddr].gr | 0xf0));
  811.                     (*(obuf + attr_count))++;
  812.                 }
  813.                 if (ea_buf[baddr].cs & CS_MASK) {
  814.                     space3270out(2);
  815.                     *obptr++ = XA_CHARSET;
  816.                     *obptr++ =
  817.                         (ea_buf[baddr].cs & CS_MASK) | 0xf0;
  818.                     trace_ds("%s", see_efa(XA_CHARSET,
  819.                         (ea_buf[baddr].cs & CS_MASK) | 0xf0));
  820.                     (*(obuf + attr_count))++;
  821.                 }
  822.             }
  823.             any = False;
  824.         } else {
  825.             insert_sa(baddr,
  826.                 ¤t_fg,
  827.                 ¤t_gr,
  828.                 ¤t_cs,
  829.                 &any);
  830.             if (ea_buf[baddr].cs & CS_GE) {
  831.                 space3270out(1);
  832.                 *obptr++ = ORDER_GE;
  833.                 if (any)
  834.                     trace_ds("'");
  835.                 trace_ds(" GraphicEscape");
  836.                 any = False;
  837.             }
  838.             space3270out(1);
  839.             *obptr++ = cg2ebc[screen_buf[baddr]];
  840.             if (cg2ebc[screen_buf[baddr]] <= 0x3f ||
  841.                 cg2ebc[screen_buf[baddr]] == 0xff) {
  842.                 if (any)
  843.                     trace_ds("'");
  844.  
  845.                 trace_ds(" %s", see_ebc(cg2ebc[screen_buf[baddr]]));
  846.                 any = False;
  847.             } else {
  848.                 if (!any)
  849.                     trace_ds(" '");
  850.                 trace_ds("%s", see_ebc(cg2ebc[screen_buf[baddr]]));
  851.                 any = True;
  852.             }
  853.         }
  854.         INC_BA(baddr);
  855.     } while (baddr != 0);
  856.     if (any)
  857.         trace_ds("'");
  858.  
  859.     trace_ds("\n");
  860.     net_output();
  861. }
  862.  
  863. #if defined(X3270_TRACE) /*[*/
  864. /*
  865.  * Construct a 3270 command to reproduce the current state of the display.
  866.  */
  867. void
  868. ctlr_snap_buffer(void)
  869. {
  870.     register int    baddr = 0;
  871.     int        attr_count;
  872.     unsigned char    current_fg = 0x00;
  873.     unsigned char    current_gr = 0x00;
  874.     unsigned char    current_cs = 0x00;
  875.     unsigned char   av;
  876.  
  877.     space3270out(2);
  878.     *obptr++ = screen_alt ? CMD_EWA : CMD_EW;
  879.     *obptr++ = code_table[0];
  880.  
  881.     do {
  882.         if (IS_FA(screen_buf[baddr])) {
  883.             space3270out(4);
  884.             *obptr++ = ORDER_SFE;
  885.             attr_count = obptr - obuf;
  886.             *obptr++ = 1; /* for now */
  887.             *obptr++ = XA_3270;
  888.             *obptr++ = code_table[calc_fa(screen_buf[baddr])];
  889.             if (ea_buf[baddr].fg) {
  890.                 space3270out(2);
  891.                 *obptr++ = XA_FOREGROUND;
  892.                 *obptr++ = ea_buf[baddr].fg;
  893.                 (*(obuf + attr_count))++;
  894.             }
  895.             if (ea_buf[baddr].gr) {
  896.                 space3270out(2);
  897.                 *obptr++ = XA_HIGHLIGHTING;
  898.                 *obptr++ = ea_buf[baddr].gr | 0xf0;
  899.                 (*(obuf + attr_count))++;
  900.             }
  901.             if (ea_buf[baddr].cs & CS_MASK) {
  902.                 space3270out(2);
  903.                 *obptr++ = XA_CHARSET;
  904.                 *obptr++ = (ea_buf[baddr].cs & CS_MASK) | 0xf0;
  905.                 (*(obuf + attr_count))++;
  906.             }
  907.         } else {
  908.             av = ea_buf[baddr].fg;
  909.             if (current_fg != av) {
  910.                 current_fg = av;
  911.                 space3270out(3);
  912.                 *obptr++ = ORDER_SA;
  913.                 *obptr++ = XA_FOREGROUND;
  914.                 *obptr++ = av;
  915.             }
  916.             av = ea_buf[baddr].gr;
  917.             if (av)
  918.                 av |= 0xf0;
  919.             if (current_gr != av) {
  920.                 current_gr = av;
  921.                 space3270out(3);
  922.                 *obptr++ = ORDER_SA;
  923.                 *obptr++ = XA_HIGHLIGHTING;
  924.                 *obptr++ = av;
  925.             }
  926.             av = ea_buf[baddr].cs & CS_MASK;
  927.             if (av)
  928.                 av |= 0xf0;
  929.             if (current_cs != av) {
  930.                 current_cs = av;
  931.                 space3270out(3);
  932.                 *obptr++ = ORDER_SA;
  933.                 *obptr++ = XA_CHARSET;
  934.                 *obptr++ = av;
  935.             }
  936.             if (ea_buf[baddr].cs & CS_GE) {
  937.                 space3270out(1);
  938.                 *obptr++ = ORDER_GE;
  939.             }
  940.             space3270out(1);
  941.             *obptr++ = cg2ebc[screen_buf[baddr]];
  942.         }
  943.         INC_BA(baddr);
  944.     } while (baddr != 0);
  945.  
  946.     space3270out(4);
  947.     *obptr++ = ORDER_SBA;
  948.     ENCODE_BADDR(obptr, cursor_addr);
  949.     *obptr++ = ORDER_IC;
  950. }
  951.  
  952. /*
  953.  * Construct a 3270 command to reproduce the reply mode.
  954.  * Returns a Boolean indicating if one is necessary.
  955.  */
  956. Boolean
  957. ctlr_snap_modes(void)
  958. {
  959.     int i;
  960.  
  961.     if (!IN_3270 || reply_mode == SF_SRM_FIELD)
  962.         return False;
  963.  
  964.     space3270out(6 + crm_nattr);
  965.     *obptr++ = CMD_WSF;
  966.     *obptr++ = 0x00;    /* implicit length */
  967.     *obptr++ = 0x00;
  968.     *obptr++ = SF_SET_REPLY_MODE;
  969.     *obptr++ = 0x00;    /* partition 0 */
  970.     *obptr++ = reply_mode;
  971.     if (reply_mode == SF_SRM_CHAR)
  972.         for (i = 0; i < crm_nattr; i++)
  973.             *obptr++ = crm_attr[i];
  974.     return True;
  975. }
  976. #endif /*]*/
  977.  
  978.  
  979. /*
  980.  * Process a 3270 Erase All Unprotected command.
  981.  */
  982. void
  983. ctlr_erase_all_unprotected(void)
  984. {
  985.     register int    baddr, sbaddr;
  986.     unsigned char    fa;
  987.     Boolean        f;
  988.  
  989.     kybd_inhibit(False);
  990.  
  991.     ALL_CHANGED;
  992.     if (formatted) {
  993.         /* find first field attribute */
  994.         baddr = 0;
  995.         do {
  996.             if (IS_FA(screen_buf[baddr]))
  997.                 break;
  998.             INC_BA(baddr);
  999.         } while (baddr != 0);
  1000.         sbaddr = baddr;
  1001.         f = False;
  1002.         do {
  1003.             fa = screen_buf[baddr];
  1004.             if (!FA_IS_PROTECTED(fa)) {
  1005.                 mdt_clear(&screen_buf[baddr]);
  1006.                 do {
  1007.                     INC_BA(baddr);
  1008.                     if (!f) {
  1009.                         cursor_move(baddr);
  1010.                         f = True;
  1011.                     }
  1012.                     if (!IS_FA(screen_buf[baddr])) {
  1013.                         ctlr_add(baddr, CG_null, 0);
  1014.                     }
  1015.                 } while (!IS_FA(screen_buf[baddr]));
  1016.             }
  1017.             else {
  1018.                 do {
  1019.                     INC_BA(baddr);
  1020.                 } while (!IS_FA(screen_buf[baddr]));
  1021.             }
  1022.         } while (baddr != sbaddr);
  1023.         if (!f)
  1024.             cursor_move(0);
  1025.     } else {
  1026.         ctlr_clear(True);
  1027.     }
  1028.     aid = AID_NO;
  1029.     do_reset(False);
  1030. }
  1031.  
  1032.  
  1033.  
  1034. /*
  1035.  * Process a 3270 Write command.
  1036.  */
  1037. void
  1038. ctlr_write(unsigned char buf[], int buflen, Boolean erase)
  1039. {
  1040.     register unsigned char    *cp;
  1041.     register int    baddr;
  1042.     unsigned char    *current_fa;
  1043.     unsigned char    new_attr;
  1044.     Boolean        last_cmd;
  1045.     Boolean        last_zpt;
  1046.     Boolean        wcc_keyboard_restore, wcc_sound_alarm;
  1047.     Boolean        ra_ge;
  1048.     int        i;
  1049.     unsigned char    na;
  1050.     int        any_fa;
  1051.     unsigned char    efa_fg;
  1052.     unsigned char    efa_gr;
  1053.     unsigned char    efa_cs;
  1054.     const char    *paren = "(";
  1055.     enum { NONE, ORDER, SBA, TEXT, NULLCH } previous = NONE;
  1056.  
  1057. #define END_TEXT0    { if (previous == TEXT) trace_ds("'"); }
  1058. #define END_TEXT(cmd)    { END_TEXT0; trace_ds(" %s", cmd); }
  1059.  
  1060. #define ATTR2FA(attr) \
  1061.     (FA_BASE | \
  1062.      (((attr) & 0x20) ? FA_PROTECT : 0) | \
  1063.      (((attr) & 0x10) ? FA_NUMERIC : 0) | \
  1064.      (((attr) & 0x01) ? FA_MODIFY : 0) | \
  1065.      (((attr) >> 2) & FA_INTENSITY))
  1066. #define START_FIELDx(fa) { \
  1067.             current_fa = &(screen_buf[buffer_addr]); \
  1068.             ctlr_add(buffer_addr, fa, 0); \
  1069.             ctlr_add_fg(buffer_addr, 0); \
  1070.             ctlr_add_gr(buffer_addr, 0); \
  1071.             trace_ds(see_attr(fa)); \
  1072.             formatted = True; \
  1073.         }
  1074. #define START_FIELD0    { START_FIELDx(FA_BASE); }
  1075. #define START_FIELD(attr) { \
  1076.             new_attr = ATTR2FA(attr); \
  1077.             START_FIELDx(new_attr); \
  1078.         }
  1079.  
  1080.     kybd_inhibit(False);
  1081.  
  1082.     if (buflen < 2)
  1083.         return;
  1084.  
  1085.     default_fg = 0;
  1086.     default_gr = 0;
  1087.     default_cs = 0;
  1088.     trace_primed = True;
  1089.     buffer_addr = cursor_addr;
  1090.     if (WCC_RESET(buf[1])) {
  1091.         if (erase)
  1092.             reply_mode = SF_SRM_FIELD;
  1093.         trace_ds("%sreset", paren);
  1094.         paren = ",";
  1095.     }
  1096.     wcc_sound_alarm = WCC_SOUND_ALARM(buf[1]);
  1097.     if (wcc_sound_alarm) {
  1098.         trace_ds("%salarm", paren);
  1099.         paren = ",";
  1100.     }
  1101.     wcc_keyboard_restore = WCC_KEYBOARD_RESTORE(buf[1]);
  1102.     if (wcc_keyboard_restore)
  1103.         ticking_stop();
  1104.     if (wcc_keyboard_restore) {
  1105.         trace_ds("%srestore", paren);
  1106.         paren = ",";
  1107.     }
  1108.  
  1109.     if (WCC_RESET_MDT(buf[1])) {
  1110.         trace_ds("%sresetMDT", paren);
  1111.         paren = ",";
  1112.         baddr = 0;
  1113.         if (appres.modified_sel)
  1114.             ALL_CHANGED;
  1115.         do {
  1116.             if (IS_FA(screen_buf[baddr])) {
  1117.                 mdt_clear(&screen_buf[baddr]);
  1118.             }
  1119.             INC_BA(baddr);
  1120.         } while (baddr != 0);
  1121.     }
  1122.     if (strcmp(paren, "("))
  1123.         trace_ds(")");
  1124.  
  1125.     last_cmd = True;
  1126.     last_zpt = False;
  1127.     current_fa = get_field_attribute(buffer_addr);
  1128.     for (cp = &buf[2]; cp < (buf + buflen); cp++) {
  1129.         switch (*cp) {
  1130.         case ORDER_SF:    /* start field */
  1131.             END_TEXT("StartField");
  1132.             if (previous != SBA)
  1133.                 trace_ds(rcba(buffer_addr));
  1134.             previous = ORDER;
  1135.             cp++;        /* skip field attribute */
  1136.             START_FIELD(*cp);
  1137.             ctlr_add_fg(buffer_addr, 0);
  1138.             INC_BA(buffer_addr);
  1139.             last_cmd = True;
  1140.             last_zpt = False;
  1141.             break;
  1142.         case ORDER_SBA:    /* set buffer address */
  1143.             cp += 2;    /* skip buffer address */
  1144.             buffer_addr = DECODE_BADDR(*(cp-1), *cp);
  1145.             END_TEXT("SetBufferAddress");
  1146.             previous = SBA;
  1147.             trace_ds(rcba(buffer_addr));
  1148.             if (buffer_addr >= COLS * ROWS) {
  1149.                 trace_ds(" [invalid address, write command terminated]\n");
  1150.                 /* Let a script go. */
  1151.                 sms_host_output();
  1152.                 return;
  1153.             }
  1154.             current_fa = get_field_attribute(buffer_addr);
  1155.             last_cmd = True;
  1156.             last_zpt = False;
  1157.             break;
  1158.         case ORDER_IC:    /* insert cursor */
  1159.             END_TEXT("InsertCursor");
  1160.             if (previous != SBA)
  1161.                 trace_ds(rcba(buffer_addr));
  1162.             previous = ORDER;
  1163.             cursor_move(buffer_addr);
  1164.             last_cmd = True;
  1165.             last_zpt = False;
  1166.             break;
  1167.         case ORDER_PT:    /* program tab */
  1168.             END_TEXT("ProgramTab");
  1169.             previous = ORDER;
  1170.             /*
  1171.              * If the buffer address is the field attribute of
  1172.              * of an unprotected field, simply advance one
  1173.              * position.
  1174.              */
  1175.             if (IS_FA(screen_buf[buffer_addr]) &&
  1176.                 !FA_IS_PROTECTED(screen_buf[buffer_addr])) {
  1177.                 INC_BA(buffer_addr);
  1178.                 last_zpt = False;
  1179.                 last_cmd = True;
  1180.                 break;
  1181.             }
  1182.             /*
  1183.              * Otherwise, advance to the first position of the
  1184.              * next unprotected field.
  1185.              */
  1186.             baddr = next_unprotected(buffer_addr);
  1187.             if (baddr < buffer_addr)
  1188.                 baddr = 0;
  1189.             /*
  1190.              * Null out the remainder of the current field -- even
  1191.              * if protected -- if the PT doesn't follow a command
  1192.              * or order, or (honestly) if the last order we saw was
  1193.              * a null-filling PT that left the buffer address at 0.
  1194.              */
  1195.             if (!last_cmd || last_zpt) {
  1196.                 trace_ds("(nulling)");
  1197.                 while ((buffer_addr != baddr) &&
  1198.                        (!IS_FA(screen_buf[buffer_addr]))) {
  1199.                     ctlr_add(buffer_addr, CG_null, 0);
  1200.                     INC_BA(buffer_addr);
  1201.                 }
  1202.                 if (baddr == 0)
  1203.                     last_zpt = True;
  1204.             } else
  1205.                 last_zpt = False;
  1206.             buffer_addr = baddr;
  1207.             last_cmd = True;
  1208.             break;
  1209.         case ORDER_RA:    /* repeat to address */
  1210.             END_TEXT("RepeatToAddress");
  1211.             cp += 2;    /* skip buffer address */
  1212.             baddr = DECODE_BADDR(*(cp-1), *cp);
  1213.             trace_ds(rcba(baddr));
  1214.             cp++;        /* skip char to repeat */
  1215.             if (*cp == ORDER_GE){
  1216.                 ra_ge = True;
  1217.                 trace_ds("GraphicEscape");
  1218.                 cp++;
  1219.             } else
  1220.                 ra_ge = False;
  1221.             previous = ORDER;
  1222.             if (*cp)
  1223.                 trace_ds("'");
  1224.             trace_ds("%s", see_ebc(*cp));
  1225.             if (*cp)
  1226.                 trace_ds("'");
  1227.             if (baddr >= COLS * ROWS) {
  1228.                 trace_ds(" [invalid address, write command terminated]\n");
  1229.                 /* Let a script go. */
  1230.                 sms_host_output();
  1231.                 return;
  1232.             }
  1233.             do {
  1234.                 if (ra_ge)
  1235.                     ctlr_add(buffer_addr, ebc2cg0[*cp],
  1236.                         CS_GE);
  1237.                 else if (default_cs)
  1238.                     ctlr_add(buffer_addr, ebc2cg0[*cp], 1);
  1239.                 else
  1240.                     ctlr_add(buffer_addr, ebc2cg[*cp], 0);
  1241.                 ctlr_add_fg(buffer_addr, default_fg);
  1242.                 ctlr_add_gr(buffer_addr, default_gr);
  1243.                 INC_BA(buffer_addr);
  1244.             } while (buffer_addr != baddr);
  1245.             current_fa = get_field_attribute(buffer_addr);
  1246.             last_cmd = True;
  1247.             last_zpt = False;
  1248.             break;
  1249.         case ORDER_EUA:    /* erase unprotected to address */
  1250.             cp += 2;    /* skip buffer address */
  1251.             baddr = DECODE_BADDR(*(cp-1), *cp);
  1252.             END_TEXT("EraseUnprotectedAll");
  1253.             if (previous != SBA)
  1254.                 trace_ds(rcba(baddr));
  1255.             previous = ORDER;
  1256.             if (baddr >= COLS * ROWS) {
  1257.                 trace_ds(" [invalid address, write command terminated]\n");
  1258.                 /* Let a script go. */
  1259.                 sms_host_output();
  1260.                 return;
  1261.             }
  1262.             do {
  1263.                 if (IS_FA(screen_buf[buffer_addr]))
  1264.                     current_fa = &(screen_buf[buffer_addr]);
  1265.                 else if (!FA_IS_PROTECTED(*current_fa)) {
  1266.                     ctlr_add(buffer_addr, CG_null, 0);
  1267.                 }
  1268.                 INC_BA(buffer_addr);
  1269.             } while (buffer_addr != baddr);
  1270.             current_fa = get_field_attribute(buffer_addr);
  1271.             last_cmd = True;
  1272.             last_zpt = False;
  1273.             break;
  1274.         case ORDER_GE:    /* graphic escape */
  1275.             END_TEXT("GraphicEscape ");
  1276.             cp++;        /* skip char */
  1277.             previous = ORDER;
  1278.             if (*cp)
  1279.                 trace_ds("'");
  1280.             trace_ds("%s", see_ebc(*cp));
  1281.             if (*cp)
  1282.                 trace_ds("'");
  1283.             ctlr_add(buffer_addr, ebc2cg0[*cp], CS_GE);
  1284.             ctlr_add_fg(buffer_addr, default_fg);
  1285.             ctlr_add_gr(buffer_addr, default_gr);
  1286.             INC_BA(buffer_addr);
  1287.             current_fa = get_field_attribute(buffer_addr);
  1288.             last_cmd = False;
  1289.             last_zpt = False;
  1290.             break;
  1291.         case ORDER_MF:    /* modify field */
  1292.             END_TEXT("ModifyField");
  1293.             if (previous != SBA)
  1294.                 trace_ds(rcba(buffer_addr));
  1295.             previous = ORDER;
  1296.             cp++;
  1297.             na = *cp;
  1298.             if (IS_FA(screen_buf[buffer_addr])) {
  1299.                 if (na == 0) {
  1300.                     INC_BA(buffer_addr);
  1301.                 } else {
  1302.                     for (i = 0; i < (int)na; i++) {
  1303.                         cp++;
  1304.                         if (*cp == XA_3270) {
  1305.                             trace_ds(" 3270");
  1306.                             cp++;
  1307.                             new_attr = ATTR2FA(*cp);
  1308.                             ctlr_add(buffer_addr,
  1309.                                 new_attr,
  1310.                                 0);
  1311.                             trace_ds(see_attr(new_attr));
  1312.                         } else if (*cp == XA_FOREGROUND) {
  1313.                             trace_ds("%s",
  1314.                                 see_efa(*cp,
  1315.                                 *(cp + 1)));
  1316.                             cp++;
  1317.                             if (appres.m3279)
  1318.                                 ctlr_add_fg(buffer_addr, *cp);
  1319.                         } else if (*cp == XA_HIGHLIGHTING) {
  1320.                             trace_ds("%s",
  1321.                                 see_efa(*cp,
  1322.                                 *(cp + 1)));
  1323.                             cp++;
  1324.                             ctlr_add_gr(buffer_addr, *cp & 0x07);
  1325.                         } else if (*cp == XA_CHARSET) {
  1326.                             int cs = 0;
  1327.  
  1328.                             trace_ds("%s",
  1329.                                 see_efa(*cp,
  1330.                                 *(cp + 1)));
  1331.                             cp++;
  1332.                             if (*cp == 0xf1)
  1333.                                 cs = 1;
  1334.                             ctlr_add(buffer_addr,
  1335.                                 screen_buf[buffer_addr], cs);
  1336.                         } else if (*cp == XA_ALL) {
  1337.                             trace_ds("%s",
  1338.                                 see_efa(*cp,
  1339.                                 *(cp + 1)));
  1340.                             cp++;
  1341.                         } else {
  1342.                             trace_ds("%s[unsupported]", see_efa(*cp, *(cp + 1)));
  1343.                             cp++;
  1344.                         }
  1345.                     }
  1346.                 }
  1347.                 INC_BA(buffer_addr);
  1348.             } else
  1349.                 cp += na * 2;
  1350.             last_cmd = True;
  1351.             last_zpt = False;
  1352.             break;
  1353.         case ORDER_SFE:    /* start field extended */
  1354.             END_TEXT("StartFieldExtended");
  1355.             if (previous != SBA)
  1356.                 trace_ds(rcba(buffer_addr));
  1357.             previous = ORDER;
  1358.             cp++;    /* skip order */
  1359.             na = *cp;
  1360.             any_fa = 0;
  1361.             efa_fg = 0;
  1362.             efa_gr = 0;
  1363.             efa_cs = 0;
  1364.             for (i = 0; i < (int)na; i++) {
  1365.                 cp++;
  1366.                 if (*cp == XA_3270) {
  1367.                     trace_ds(" 3270");
  1368.                     cp++;
  1369.                     START_FIELD(*cp);
  1370.                     any_fa++;
  1371.                 } else if (*cp == XA_FOREGROUND) {
  1372.                     trace_ds("%s", see_efa(*cp, *(cp + 1)));
  1373.                     cp++;
  1374.                     if (appres.m3279)
  1375.                         efa_fg = *cp;
  1376.                 } else if (*cp == XA_HIGHLIGHTING) {
  1377.                     trace_ds("%s", see_efa(*cp, *(cp + 1)));
  1378.                     cp++;
  1379.                     efa_gr = *cp & 0x07;
  1380.                 } else if (*cp == XA_CHARSET) {
  1381.                     trace_ds("%s", see_efa(*cp, *(cp + 1)));
  1382.                     cp++;
  1383.                     if (*cp == 0xf1)
  1384.                         efa_cs = 1;
  1385.                 } else if (*cp == XA_ALL) {
  1386.                     trace_ds("%s", see_efa(*cp, *(cp + 1)));
  1387.                     cp++;
  1388.                 } else {
  1389.                     trace_ds("%s[unsupported]", see_efa(*cp, *(cp + 1)));
  1390.                     cp++;
  1391.                 }
  1392.             }
  1393.             if (!any_fa)
  1394.                 START_FIELD0;
  1395.             ctlr_add(buffer_addr, screen_buf[buffer_addr], efa_cs);
  1396.             ctlr_add_fg(buffer_addr, efa_fg);
  1397.             ctlr_add_gr(buffer_addr, efa_gr);
  1398.             INC_BA(buffer_addr);
  1399.             last_cmd = True;
  1400.             last_zpt = False;
  1401.             break;
  1402.         case ORDER_SA:    /* set attribute */
  1403.             END_TEXT("SetAttribtue");
  1404.             previous = ORDER;
  1405.             cp++;
  1406.             if (*cp == XA_FOREGROUND)  {
  1407.                 trace_ds("%s", see_efa(*cp, *(cp + 1)));
  1408.                 if (appres.m3279)
  1409.                     default_fg = *(cp + 1);
  1410.             } else if (*cp == XA_HIGHLIGHTING)  {
  1411.                 trace_ds("%s", see_efa(*cp, *(cp + 1)));
  1412.                 default_gr = *(cp + 1) & 0x07;
  1413.             } else if (*cp == XA_ALL)  {
  1414.                 trace_ds("%s", see_efa(*cp, *(cp + 1)));
  1415.                 default_fg = 0;
  1416.                 default_gr = 0;
  1417.                 default_cs = 0;
  1418.             } else if (*cp == XA_CHARSET) {
  1419.                 trace_ds("%s", see_efa(*cp, *(cp + 1)));
  1420.                 default_cs = (*(cp + 1) == 0xf1) ? 1 : 0;
  1421.             } else
  1422.                 trace_ds("%s[unsupported]",
  1423.                     see_efa(*cp, *(cp + 1)));
  1424.             cp++;
  1425.             last_cmd = True;
  1426.             last_zpt = False;
  1427.             break;
  1428.         case FCORDER_SUB:    /* format control orders */
  1429.         case FCORDER_DUP:
  1430.         case FCORDER_FM:
  1431.         case FCORDER_FF:
  1432.         case FCORDER_CR:
  1433.         case FCORDER_NL:
  1434.         case FCORDER_EM:
  1435.         case FCORDER_EO:
  1436.             END_TEXT(see_ebc(*cp));
  1437.             previous = ORDER;
  1438.             ctlr_add(buffer_addr, ebc2cg[*cp], default_cs);
  1439.             ctlr_add_fg(buffer_addr, default_fg);
  1440.             ctlr_add_gr(buffer_addr, default_gr);
  1441.             INC_BA(buffer_addr);
  1442.             last_cmd = True;
  1443.             last_zpt = False;
  1444.             break;
  1445.         case FCORDER_NULL:
  1446.             END_TEXT("NULL");
  1447.             previous = NULLCH;
  1448.             ctlr_add(buffer_addr, ebc2cg[*cp], default_cs);
  1449.             ctlr_add_fg(buffer_addr, default_fg);
  1450.             ctlr_add_gr(buffer_addr, default_gr);
  1451.             INC_BA(buffer_addr);
  1452.             last_cmd = False;
  1453.             last_zpt = False;
  1454.             break;
  1455.         default:    /* enter character */
  1456.             if (*cp <= 0x3F) {
  1457.                 END_TEXT("ILLEGAL_ORDER");
  1458.                 trace_ds("%s", see_ebc(*cp));
  1459.                 last_cmd = True;
  1460.                 last_zpt = False;
  1461.                 break;
  1462.             }
  1463.             if (previous != TEXT)
  1464.                 trace_ds(" '");
  1465.             previous = TEXT;
  1466.             trace_ds("%s", see_ebc(*cp));
  1467.             ctlr_add(buffer_addr, ebc2cg[*cp], default_cs);
  1468.             ctlr_add_fg(buffer_addr, default_fg);
  1469.             ctlr_add_gr(buffer_addr, default_gr);
  1470.             INC_BA(buffer_addr);
  1471.             last_cmd = False;
  1472.             last_zpt = False;
  1473.             break;
  1474.         }
  1475.     }
  1476.     set_formatted();
  1477.     END_TEXT0;
  1478.     trace_ds("\n");
  1479.     if (wcc_keyboard_restore) {
  1480.         aid = AID_NO;
  1481.         do_reset(False);
  1482.     } else if (kybdlock & KL_OIA_TWAIT) {
  1483.         kybdlock_clr(KL_OIA_TWAIT, "ctlr_write");
  1484.         status_syswait();
  1485.     }
  1486.     if (wcc_sound_alarm)
  1487.         ring_bell();
  1488.  
  1489.     trace_primed = False;
  1490.  
  1491.     ps_process();
  1492.  
  1493.     /* Let a script go. */
  1494.     sms_host_output();
  1495. }
  1496.  
  1497. #undef START_FIELDx
  1498. #undef START_FIELD0
  1499. #undef START_FIELD
  1500. #undef END_TEXT0
  1501. #undef END_TEXT
  1502.  
  1503. /*
  1504.  * Write SSCP-LU data, which is quite a bit dumber than regular 3270
  1505.  * output.
  1506.  */
  1507. void
  1508. ctlr_write_sscp_lu(unsigned char buf[], int buflen)
  1509. {
  1510.     int i;
  1511.     unsigned char *cp = buf;
  1512.     int s_row;
  1513.     unsigned char c;
  1514.     int baddr;
  1515.     unsigned char fa;
  1516.  
  1517.     /*
  1518.      * The 3174 Functionl Description says that anything but NL, NULL, FM,
  1519.      * or DUP is to be displayed as a graphic.  However, to deal with
  1520.      * badly-behaved hosts, we filter out SF, IC and SBA sequences, and
  1521.      * we display other control codes as spaces.
  1522.      */
  1523.  
  1524.     trace_ds("SSCP-LU data\n");
  1525.     for (i = 0; i < buflen; cp++, i++) {
  1526.         switch (*cp) {
  1527.         case FCORDER_NL:
  1528.             /*
  1529.              * Insert NULLs to the end of the line and advance to
  1530.              * the beginning of the next line.
  1531.              */
  1532.             s_row = buffer_addr / COLS;
  1533.             while ((buffer_addr / COLS) == s_row) {
  1534.                 ctlr_add(buffer_addr, ebc2cg[0], default_cs);
  1535.                 ctlr_add_fg(buffer_addr, default_fg);
  1536.                 ctlr_add_gr(buffer_addr, default_gr);
  1537.                 INC_BA(buffer_addr);
  1538.             }
  1539.             break;
  1540.  
  1541.         case ORDER_SF:    /* some hosts forget their talking SSCP-LU */
  1542.             cp++;
  1543.             i++;
  1544.             fa = ATTR2FA(*cp);
  1545.             trace_ds(" StartField%s %s [translated to space]\n",
  1546.                 rcba(buffer_addr), see_attr(fa));
  1547.             ctlr_add(buffer_addr, CG_space, default_cs);
  1548.             ctlr_add_fg(buffer_addr, default_fg);
  1549.             ctlr_add_gr(buffer_addr, default_gr);
  1550.             INC_BA(buffer_addr);
  1551.             break;
  1552.         case ORDER_IC:
  1553.             trace_ds(" InsertCursor%s [ignored]\n",
  1554.                 rcba(buffer_addr));
  1555.             break;
  1556.         case ORDER_SBA:
  1557.             baddr = DECODE_BADDR(*(cp+1), *(cp+2));
  1558.             trace_ds(" SetBufferAddress%s [ignored]\n", rcba(baddr));
  1559.             cp += 2;
  1560.             i += 2;
  1561.             break;
  1562.  
  1563.         case ORDER_GE:
  1564.             cp++;
  1565.             if (++i >= buflen)
  1566.                 break;
  1567.             if (*cp <= 0x40)
  1568.                 c = CG_space;
  1569.             else
  1570.                 c = ebc2cg0[*cp];
  1571.             ctlr_add(buffer_addr, c, CS_GE);
  1572.             ctlr_add_fg(buffer_addr, default_fg);
  1573.             ctlr_add_gr(buffer_addr, default_gr);
  1574.             INC_BA(buffer_addr);
  1575.             break;
  1576.  
  1577.         default:
  1578.             if (*cp == FCORDER_NULL)
  1579.                 c = CG_space;
  1580.             else if (*cp == FCORDER_FM)
  1581.                 c = CG_asterisk;
  1582.             else if (*cp == FCORDER_DUP)
  1583.                 c = CG_semicolon;
  1584.             else if (*cp < 0x40) {
  1585.                 trace_ds(" X'%02x') [translated to space]\n",
  1586.                     *cp);
  1587.                 c = CG_space; /* technically not necessary */
  1588.             } else
  1589.                 c = ebc2cg[*cp];
  1590.             ctlr_add(buffer_addr, c, default_cs);
  1591.             ctlr_add_fg(buffer_addr, default_fg);
  1592.             ctlr_add_gr(buffer_addr, default_gr);
  1593.             INC_BA(buffer_addr);
  1594.             break;
  1595.         }
  1596.     }
  1597.     cursor_move(buffer_addr);
  1598.     sscp_start = buffer_addr;
  1599.  
  1600.     /* Unlock the keyboard. */
  1601.     aid = AID_NO;
  1602.     do_reset(False);
  1603.  
  1604.     /* Let a script go. */
  1605.     sms_host_output();
  1606. }
  1607.  
  1608. /*
  1609.  * Process pending input.
  1610.  */
  1611. void
  1612. ps_process(void)
  1613. {
  1614.     while (run_ta())
  1615.         ;
  1616.     sms_continue();
  1617.  
  1618.     /* Process file transfers. */
  1619.     if (ft_state != FT_NONE &&      /* transfer in progress */
  1620.         formatted &&                /* screen is formatted */
  1621.         !screen_alt &&              /* 24x80 screen */
  1622.         !kybdlock &&                /* keyboard not locked */
  1623.         /* magic field */
  1624.         IS_FA(screen_buf[1919]) && FA_IS_SKIP(screen_buf[1919])) {
  1625.         ft_cut_data();
  1626.     }
  1627. }
  1628.  
  1629. /*
  1630.  * Tell me if there is any data on the screen.
  1631.  */
  1632. Boolean
  1633. ctlr_any_data(void)
  1634. {
  1635.     register unsigned char *c = screen_buf;
  1636.     register int i;
  1637.     register unsigned char oc;
  1638.  
  1639.     for (i = 0; i < ROWS*COLS; i++) {
  1640.         oc = *c++;
  1641.         if (!IS_FA(oc) && !IsBlank(oc))
  1642.             return True;
  1643.     }
  1644.     return False;
  1645. }
  1646.  
  1647. /*
  1648.  * Clear the text (non-status) portion of the display.  Also resets the cursor
  1649.  * and buffer addresses and extended attributes.
  1650.  */
  1651. void
  1652. ctlr_clear(Boolean can_snap)
  1653. {
  1654.     /* Snap any data that is about to be lost into the trace file. */
  1655.     if (ctlr_any_data()) {
  1656. #if defined(X3270_TRACE) /*[*/
  1657.         if (can_snap && !trace_skipping && toggled(SCREEN_TRACE))
  1658.             trace_screen();
  1659. #endif /*]*/
  1660.         scroll_save(maxROWS, ever_3270 ? False : True);
  1661.     }
  1662. #if defined(X3270_TRACE) /*[*/
  1663.     trace_skipping = False;
  1664. #endif /*]*/
  1665.  
  1666.     /* Clear the screen. */
  1667.     (void) memset((char *)screen_buf, 0, ROWS*COLS);
  1668.     (void) memset((char *)ea_buf, 0, ROWS*COLS*sizeof(struct ea));
  1669.     ALL_CHANGED;
  1670.     cursor_move(0);
  1671.     buffer_addr = 0;
  1672.     unselect(0, ROWS*COLS);
  1673.     formatted = False;
  1674.     default_fg = 0;
  1675.     default_gr = 0;
  1676.     sscp_start = 0;
  1677. }
  1678.  
  1679. /*
  1680.  * Fill the screen buffer with blanks.
  1681.  */
  1682. static void
  1683. ctlr_blanks(void)
  1684. {
  1685.     (void) memset((char *)screen_buf, CG_space, ROWS*COLS);
  1686.     ALL_CHANGED;
  1687.     cursor_move(0);
  1688.     buffer_addr = 0;
  1689.     unselect(0, ROWS*COLS);
  1690.     formatted = False;
  1691. }
  1692.  
  1693.  
  1694. /*
  1695.  * Change a character in the 3270 buffer.
  1696.  */
  1697. void
  1698. ctlr_add(int baddr, unsigned char c, unsigned char cs)
  1699. {
  1700.     unsigned char oc;
  1701.  
  1702.     if ((oc = screen_buf[baddr]) != c || ea_buf[baddr].cs != cs) {
  1703.         if (trace_primed && !IsBlank(oc)) {
  1704. #if defined(X3270_TRACE) /*[*/
  1705.             if (toggled(SCREEN_TRACE))
  1706.                 trace_screen();
  1707. #endif /*]*/
  1708.             scroll_save(maxROWS, False);
  1709.             trace_primed = False;
  1710.         }
  1711.         if (SELECTED(baddr))
  1712.             unselect(baddr, 1);
  1713.         ONE_CHANGED(baddr);
  1714.         screen_buf[baddr] = c;
  1715.         ea_buf[baddr].cs = cs;
  1716.     }
  1717. }
  1718.  
  1719. /*
  1720.  * Change the graphic rendition of a character in the 3270 buffer.
  1721.  */
  1722. void
  1723. ctlr_add_gr(int baddr, unsigned char gr)
  1724. {
  1725.     if (ea_buf[baddr].gr != gr) {
  1726.         if (SELECTED(baddr))
  1727.             unselect(baddr, 1);
  1728.         ONE_CHANGED(baddr);
  1729.         ea_buf[baddr].gr = gr;
  1730.         if (gr & GR_BLINK)
  1731.             blink_start();
  1732.     }
  1733. }
  1734.  
  1735. /*
  1736.  * Change the foreground color for a character in the 3270 buffer.
  1737.  */
  1738. void
  1739. ctlr_add_fg(int baddr, unsigned char color)
  1740. {
  1741.     if (!appres.m3279)
  1742.         return;
  1743.     if ((color & 0xf0) != 0xf0)
  1744.         color = 0;
  1745.     if (ea_buf[baddr].fg != color) {
  1746.         if (SELECTED(baddr))
  1747.             unselect(baddr, 1);
  1748.         ONE_CHANGED(baddr);
  1749.         ea_buf[baddr].fg = color;
  1750.     }
  1751. }
  1752.  
  1753. #if defined(X3270_ANSI) /*[*/
  1754. /*
  1755.  * Change the background color for a character in the 3270 buffer.
  1756.  */
  1757. void
  1758. ctlr_add_bg(int baddr, unsigned char color)
  1759. {
  1760.     if (!appres.m3279)
  1761.         return;
  1762.     if ((color & 0xf0) != 0xf0)
  1763.         color = 0;
  1764.     if (ea_buf[baddr].bg != color) {
  1765.         if (SELECTED(baddr))
  1766.             unselect(baddr, 1);
  1767.         ONE_CHANGED(baddr);
  1768.         ea_buf[baddr].bg = color;
  1769.     }
  1770. }
  1771. #endif /*]*/
  1772.  
  1773. /*
  1774.  * Copy a block of characters in the 3270 buffer, optionally including all of
  1775.  * the extended attributes.  (The character set, which is actually kept in the
  1776.  * extended attributes, is considered part of the characters here.)
  1777.  */
  1778. void
  1779. ctlr_bcopy(int baddr_from, int baddr_to, int count, int move_ea)
  1780. {
  1781.     /* Move the characters. */
  1782.     if (memcmp((char *) &screen_buf[baddr_from],
  1783.                (char *) &screen_buf[baddr_to],
  1784.            count)) {
  1785.         (void) memmove(&screen_buf[baddr_to], &screen_buf[baddr_from],
  1786.                        count);
  1787.         REGION_CHANGED(baddr_to, baddr_to + count);
  1788.         /*
  1789.          * For the time being, if any selected text shifts around on
  1790.          * the screen, unhighlight it.  Eventually there should be
  1791.          * logic for preserving the highlight if the *all* of the
  1792.          * selected text moves.
  1793.          */
  1794.         if (area_is_selected(baddr_to, count))
  1795.             unselect(baddr_to, count);
  1796.     }
  1797.  
  1798.     /*
  1799.      * If we aren't supposed to move all the extended attributes, move
  1800.      * the character sets separately.
  1801.      */
  1802.     if (!move_ea) {
  1803.         int i;
  1804.         int any = 0;
  1805.         int start, end, inc;
  1806.  
  1807.         if (baddr_to < baddr_from || baddr_from + count < baddr_to) {
  1808.             /* Scan forward. */
  1809.             start = 0;
  1810.             end = count + 1;
  1811.             inc = 1;
  1812.         } else {
  1813.             /* Scan backward. */
  1814.             start = count - 1;
  1815.             end = -1;
  1816.             inc = -1;
  1817.         }
  1818.  
  1819.         for (i = start; i != end; i += inc) {
  1820.             if (ea_buf[baddr_to+i].cs != ea_buf[baddr_from+i].cs) {
  1821.                 ea_buf[baddr_to+i].cs = ea_buf[baddr_from+i].cs;
  1822.                 REGION_CHANGED(baddr_to + i, baddr_to + i + 1);
  1823.                 any++;
  1824.             }
  1825.         }
  1826.         if (any && area_is_selected(baddr_to, count))
  1827.             unselect(baddr_to, count);
  1828.     }
  1829.  
  1830.     /* Move extended attributes. */
  1831.     if (move_ea && memcmp((char *) &ea_buf[baddr_from],
  1832.                   (char *) &ea_buf[baddr_to],
  1833.                   count*sizeof(struct ea))) {
  1834.         (void) memmove(&ea_buf[baddr_to], &ea_buf[baddr_from],
  1835.                        count*sizeof(struct ea));
  1836.         REGION_CHANGED(baddr_to, baddr_to + count);
  1837.     }
  1838. }
  1839.  
  1840. #if defined(X3270_ANSI) /*[*/
  1841. /*
  1842.  * Erase a region of the 3270 buffer, optionally clearing extended attributes
  1843.  * as well.
  1844.  */
  1845. void
  1846. ctlr_aclear(int baddr, int count, int clear_ea)
  1847. {
  1848.     if (memcmp((char *) &screen_buf[baddr], (char *) zero_buf, count)) {
  1849.         (void) memset((char *) &screen_buf[baddr], 0, count);
  1850.         REGION_CHANGED(baddr, baddr + count);
  1851.         if (area_is_selected(baddr, count))
  1852.             unselect(baddr, count);
  1853.     }
  1854.     if (clear_ea && memcmp((char *) &ea_buf[baddr], (char *) zero_buf, count*sizeof(struct ea))) {
  1855.         (void) memset((char *) &ea_buf[baddr], 0, count*sizeof(struct ea));
  1856.         REGION_CHANGED(baddr, baddr + count);
  1857.     }
  1858. }
  1859.  
  1860. /*
  1861.  * Scroll the screen 1 row.
  1862.  *
  1863.  * This could be accomplished with ctlr_bcopy() and ctlr_aclear(), but this
  1864.  * operation is common enough to warrant a separate path.
  1865.  */
  1866. void
  1867. ctlr_scroll(void)
  1868. {
  1869.     int qty = (ROWS - 1) * COLS;
  1870.     Boolean obscured;
  1871.  
  1872.     /* Make sure nothing is selected. (later this can be fixed) */
  1873.     unselect(0, ROWS*COLS);
  1874.  
  1875.     /* Synchronize pending changes prior to this. */
  1876.     obscured = screen_obscured();
  1877.     if (!obscured && screen_changed)
  1878.         screen_disp();
  1879.  
  1880.     /* Move screen_buf and ea_buf. */
  1881.     (void) memmove(&screen_buf[0], &screen_buf[COLS], qty);
  1882.     (void) memmove(&ea_buf[0], &ea_buf[COLS],
  1883.         qty * sizeof(struct ea));
  1884.  
  1885.     /* Clear the last line. */
  1886.     (void) memset((char *) &screen_buf[qty], 0, COLS);
  1887.     (void) memset((char *) &ea_buf[qty], 0, COLS * sizeof(struct ea));
  1888.  
  1889.     /* Update the screen. */
  1890.     if (obscured) {
  1891.         ALL_CHANGED;
  1892.     } else {
  1893.         screen_scroll();
  1894.     }
  1895. }
  1896. #endif /*]*/
  1897.  
  1898. /*
  1899.  * Note that a particular region of the screen has changed.
  1900.  */
  1901. void
  1902. ctlr_changed(int bstart, int bend)
  1903. {
  1904.     REGION_CHANGED(bstart, bend);
  1905. }
  1906.  
  1907. #if defined(X3270_ANSI) /*[*/
  1908. /*
  1909.  * Swap the regular and alternate screen buffers
  1910.  */
  1911. void
  1912. ctlr_altbuffer(Boolean alt)
  1913. {
  1914.     unsigned char *stmp;
  1915.     struct ea *etmp;
  1916.  
  1917.     if (alt != is_altbuffer) {
  1918.  
  1919.         stmp = screen_buf;
  1920.         screen_buf = ascreen_buf;
  1921.         ascreen_buf = stmp;
  1922.  
  1923.         etmp = ea_buf;
  1924.         ea_buf = aea_buf;
  1925.         aea_buf = etmp;
  1926.  
  1927.         is_altbuffer = alt;
  1928.         ALL_CHANGED;
  1929.         unselect(0, ROWS*COLS);
  1930.  
  1931.         /*
  1932.          * There may be blinkers on the alternate screen; schedule one
  1933.          * iteration just in case.
  1934.          */
  1935.         blink_start();
  1936.     }
  1937. }
  1938. #endif /*]*/
  1939.  
  1940.  
  1941. /*
  1942.  * Set or clear the MDT on an attribute
  1943.  */
  1944. void
  1945. mdt_set(unsigned char *fa)
  1946. {
  1947.     if (*fa & FA_MODIFY)
  1948.         return;
  1949.     *fa |= FA_MODIFY;
  1950.     if (appres.modified_sel)
  1951.         ALL_CHANGED;
  1952. }
  1953.  
  1954. void
  1955. mdt_clear(unsigned char *fa)
  1956. {
  1957.     if (!(*fa & FA_MODIFY))
  1958.         return;
  1959.     *fa &= ~FA_MODIFY;
  1960.     if (appres.modified_sel)
  1961.         ALL_CHANGED;
  1962. }
  1963.  
  1964.  
  1965. /*
  1966.  * Support for screen-size swapping for scrolling
  1967.  */
  1968. void
  1969. ctlr_shrink(void)
  1970. {
  1971.     (void) memset((char *)screen_buf,
  1972.         *debugging_font ? CG_space : CG_null,
  1973.         ROWS*COLS);
  1974.     ALL_CHANGED;
  1975.     screen_disp();
  1976. }
  1977.  
  1978.  
  1979. /*
  1980.  * Transaction timing.  The time between sending an interrupt (PF, PA, Enter,
  1981.  * Clear) and the host unlocking the keyboard is indicated on the status line
  1982.  * to an accuracy of 0.1 seconds.  If we don't repaint the screen before we see
  1983.  * the unlock, the time should be fairly accurate.
  1984.  */
  1985. static struct timeval t_start;
  1986. static Boolean ticking = False;
  1987. static unsigned long tick_id;
  1988. static struct timeval t_want;
  1989.  
  1990. /* Return the difference in milliseconds between two timevals. */
  1991. static long
  1992. delta_msec(struct timeval *t1, struct timeval *t0)
  1993. {
  1994.     return (t1->tv_sec - t0->tv_sec) * 1000 +
  1995.            (t1->tv_usec - t0->tv_usec + 500) / 1000;
  1996. }
  1997.  
  1998. static void
  1999. keep_ticking(void)
  2000. {
  2001.     struct timeval t1;
  2002.     long msec;
  2003.  
  2004.     do {
  2005.         (void) gettimeofday(&t1, (struct timezone *) 0);
  2006.         t_want.tv_sec++;
  2007.         msec = delta_msec(&t_want, &t1);
  2008.     } while (msec <= 0);
  2009.     tick_id = AddTimeOut(msec, keep_ticking);
  2010.     status_timing(&t_start, &t1);
  2011. }
  2012.  
  2013. void
  2014. ticking_start(Boolean anyway)
  2015. {
  2016.     if (!toggled(SHOW_TIMING) && !anyway)
  2017.         return;
  2018.     status_untiming();
  2019.     if (ticking)
  2020.         RemoveTimeOut(tick_id);
  2021.     ticking = True;
  2022.     (void) gettimeofday(&t_start, (struct timezone *) 0);
  2023.     tick_id = AddTimeOut(1000, keep_ticking);
  2024.     t_want = t_start;
  2025. }
  2026.  
  2027. static void
  2028. ticking_stop(void)
  2029. {
  2030.     struct timeval t1;
  2031.  
  2032.     if (!ticking)
  2033.         return;
  2034.     RemoveTimeOut(tick_id);
  2035.     (void) gettimeofday(&t1, (struct timezone *) 0);
  2036.     ticking = False;
  2037.     status_timing(&t_start, &t1);
  2038. }
  2039.  
  2040. void
  2041. toggle_showTiming(struct toggle *t unused, enum toggle_type tt unused)
  2042. {
  2043.     if (!toggled(SHOW_TIMING))
  2044.         status_untiming();
  2045. }
  2046.  
  2047.  
  2048. /*
  2049.  * No-op toggle.
  2050.  */
  2051. void
  2052. toggle_nop(struct toggle *t unused, enum toggle_type tt unused)
  2053. {
  2054. }
  2055.